package com.upb.webserver.chain;

import com.upb.webserver.account.AccountService;
import com.upb.webserver.common.pojo.account.AccountCommon;
import com.upb.webserver.common.pojo.base.BasePageResponse;
import com.upb.webserver.common.pojo.base.BaseResponse;
import com.upb.webserver.common.pojo.chain.ChainVO;
import com.upb.webserver.common.pojo.chain.ReqAddRunningFiscoChainVO;
import com.upb.webserver.common.pojo.order.ReqAddWorkOrderOfNewChainVO;
import com.upb.webserver.common.pojo.order.ReqUpdateWorkOrderOfNewChainVO;
import com.upb.webserver.common.pojo.order.RspChainDeployVO;
import com.upb.webserver.common.pojo.order.RspNodeHostListInitVO;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.fisco.chain.FiscoChainService;
import com.upb.webserver.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Set;

/**
 * public controller for fisco/fabric chain deploy api
 *
 * @case1: developer wanna deploy chain, than choose fisco or fabric,
 * then call fabricChainService or fiscoChainService and save chain info and create work order,
 * then devOps handle with deploying, call fabricChainMgrRest or fiscoRest, and update work order status
 */
@Slf4j
@RestController
@RequestMapping(value = "chain")
public class ChainController {
    @Autowired
    private FiscoChainService fiscoChainService;
    @Autowired
    private ChainService chainService;
    @Autowired
    private DeleteChainService deleteChainService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private OrderService orderService;


    /**
     * add new fabric chain.
     *
     * @param param
     * @param result
     * @return
     */
    @PostMapping(value = "work-order-of-new-chain")
    public BaseResponse addWorkOrderOfNewChain(@RequestBody @Valid ReqAddWorkOrderOfNewChainVO param, BindingResult result, HttpServletRequest request) {
        log.info("start exec method [addWorkOrderOfNewChain]. param:{}", JsonUtils.objToString(param));
        AccountCommon accountCommon = accountService.getAccountCommon(request);
        RspChainDeployVO rspChainDeployVO = orderService.addWorkOrderOfNewChain(accountCommon.getPlatform(), accountCommon.getId(), accountCommon.getAccount(), param);
        BaseResponse baseResponse =new BaseResponse(ConstantCode.SUCCESS);
        baseResponse.setData(rspChainDeployVO);
        log.info("success exec method [addWorkOrderOfNewChain]. baseResponse:{}",JsonUtils.objToString(baseResponse));
        return baseResponse;
    }


    /**
     * @param param
     * @param result
     * @param request
     * @return
     */
    @PutMapping(value = "work-order-of-new-chain")
    public BaseResponse updateWorkOrderOfNewChain(@RequestBody @Valid ReqUpdateWorkOrderOfNewChainVO param, BindingResult result, HttpServletRequest request) {
        log.info("start exec method [updateWorkOrderOfNewChain]. param:{}", JsonUtils.objToString(param));
        AccountCommon accountCommon = accountService.getAccountCommon(request);
        orderService.updateWorkOrderOfNewChain(accountCommon.getPlatform(), accountCommon.getId(), accountCommon.getAccount(), param);
        log.info("success exec method [updateWorkOrderOfNewChain].");
        return new BaseResponse(ConstantCode.SUCCESS);
    }


    /**
     * @param pageNumber
     * @param pageSize
     * @param status
     * @param request
     * @return
     */
    @GetMapping(value = "list")
    public BasePageResponse queryChainByPage(@RequestParam("pageNumber") Integer pageNumber,
                                             @RequestParam("pageSize") Integer pageSize,
                                             @RequestParam(value = "status") Set<Byte> status,
                                             HttpServletRequest request) {
        log.info("start exec method [queryChainByPage]. pageNumber:{} pageSize:{} status:{}", pageNumber, pageSize, status);
        //get AccountCommon
        AccountCommon accountCommon = accountService.getAccountCommon(request);
        BasePageResponse response = chainService.queryChainByPage(accountCommon.getPlatform(), accountCommon.getId(), accountCommon.getRoleName(), status, pageNumber, pageSize);
        log.info("success exec method [queryChainByPage]. result:{}", JsonUtils.objToString(response));
        return response;
    }


    /**
     * @param workOrderId
     * @return
     */
    @PatchMapping(value = "work-order-of-new-chain/{workOrderId}/deploy")
    public BaseResponse deployNewChain(@PathVariable("workOrderId") Integer workOrderId,
                                       @RequestParam(value = "dockerImageType", required = false) Byte dockerImageType) {

        log.info("start exec method [deployNewChain]. workOrderId:{}", workOrderId);
        RspChainDeployVO rspChainDeployVO = orderService.chainDeploy(workOrderId, dockerImageType);
        BaseResponse baseResponse = new BaseResponse(ConstantCode.SUCCESS, rspChainDeployVO);
        log.info("success exec method [deployNewChain]. result:{}", JsonUtils.objToString(baseResponse));
        return baseResponse;
    }

    /**
     * @param workOrderId
     * @param dockerImageType
     * @return
     */
    @PostMapping(value = "work-order-of-new-chain/{workOrderId}/initNodeHost")
    public BaseResponse initHostOfNewChain(@PathVariable("workOrderId") Integer workOrderId,
                                           @RequestParam(value = "dockerImageType", required = false) Byte dockerImageType) {

        log.info("start exec method [initHostOfNewChain]. workOrderId:{}", workOrderId);
        RspNodeHostListInitVO initNodeHostList = orderService.initNodeHostList(workOrderId, dockerImageType);
        BaseResponse baseResponse = new BaseResponse(ConstantCode.SUCCESS);
        baseResponse.setData(initNodeHostList);
        log.info("finish exec method [initHostOfNewChain]. result:{}", JsonUtils.objToString(baseResponse));
        return baseResponse;
    }


    /**
     * @param chainId
     * @return
     */
    @GetMapping(value = "/{chainId}/detail")
    public BaseResponse queryChainDetail(@PathVariable("chainId") Integer chainId) {
        log.info("start exec method [queryChainDetail]. chainId:{}", chainId);

        ChainVO chainVO = chainService.getChainDetail(chainId);
        BaseResponse baseResponse = new BaseResponse(ConstantCode.SUCCESS, chainVO);
        log.info("success exec method [queryChainDetail]. result:{}", JsonUtils.objToString(baseResponse));
        return baseResponse;
    }

    /**
     * @param chainId
     * @return
     */
    @DeleteMapping(value = "/{chainId}")
    public BaseResponse deleteByChainId(@PathVariable("chainId") Integer chainId, HttpServletRequest request) {
        log.info("start exec method [deleteByChainId]. chainId:{}", chainId);
        AccountCommon accountCommon = accountService.getAccountCommon(request);
        deleteChainService.deleteByChainId(accountCommon.getAccount(), chainId);
        BaseResponse baseResponse = new BaseResponse(ConstantCode.SUCCESS);
        log.info("success exec method [deleteByChainId]. result:{}", JsonUtils.objToString(baseResponse));
        return baseResponse;
    }


    /**
     * @param chainType
     * @return
     */
    @GetMapping(value = "/image/type/list")
    public BaseResponse queryImageTypeList(@RequestParam(value = "chainType") Byte chainType) {
        log.info("start exec method [queryImageTypeList]. chainType:{}", chainType);
        BaseResponse baseResponse = chainService.queryImageTypeList(chainType);
        log.info("success exec method [queryImageTypeList]. result:{}", JsonUtils.objToString(baseResponse));
        return baseResponse;
    }


    /**
     * @param param
     * @param result
     * @param request
     * @return
     */
    @PostMapping(value = "running-fisco-chain")
    public BaseResponse addRunningFiscoChain(@RequestBody @Valid ReqAddRunningFiscoChainVO param, BindingResult result, HttpServletRequest request) {
        log.info("start exec method [addRunningFiscoChain]. param:{}", JsonUtils.objToString(param));
        AccountCommon accountCommon = accountService.getAccountCommon(request);
        fiscoChainService.addRunningFiscoChain(accountCommon.getPlatform(), accountCommon.getId(), param);
        log.info("success exec method [addRunningFiscoChain].");
        return new BaseResponse(ConstantCode.SUCCESS);
    }
}
